#include <optional>
#include <nice2d/util.h>
#include <nice2d/entity.h>
#include <nice2d/actions/movementaction.h>

class MovementActionData
{
public:
    sf::Vector2f oldPosition;
    sf::Vector2f destination;
    bool relative = false;
    std::optional<sf::Vector2f> velocity;
};

MovementAction::MovementAction(float duration):
    FiniteTimeAction(duration),
    data(new MovementActionData())
{
}

MovementAction::~MovementAction()
{
}

void MovementAction::setTargetPosition(const sf::Vector2f &position, bool relativePosition)
{
    data->destination = position;
    data->relative = relativePosition;
}

sf::Vector2f MovementAction::getTargetPosition() const
{
    return data->destination;
}

sf::Vector2f MovementAction::getOldPosition() const
{
    return data->oldPosition;
}

void MovementAction::update(float deltaTime)
{
    if (getOwner().expired())
        return;

    auto target = std::dynamic_pointer_cast<Entity>(getOwner().lock());

    if (!data->velocity.has_value()) {
        data->oldPosition = target->getPosition();
        if (data->relative)
            data->destination += target->getPosition();
        data->velocity = (data->destination - target->getPosition()) / getDuration();
    }

    auto oldPosition = target->getPosition();
    auto delta = data->velocity.value() * deltaTime;
    target->move(delta.x, delta.y);

    auto position = target->getPosition();

    float oldDistance2 = distance2(oldPosition, getTargetPosition());
    float currentDistance2 = distance2(position, getTargetPosition());
    if (currentDistance2 >= oldDistance2) {
        target->setPosition(getTargetPosition());
        stop();
    }
}
